home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.mactech.com 2010
/
ftp.mactech.com.tar
/
ftp.mactech.com
/
machack
/
Hacks97
/
CrashBurn.sit
/
Crash & Burn
/
source code
/
Flames.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1997-06-27
|
7KB
|
307 lines
#include "flames.h"
#include <stdlib.h>
#include <time.h>
#define Max(x, y) ((x) > (y) ? (x) : (y))
#define Min(x, y) ((x) < (y) ? (x) : (y))
#define random(val) (rand() % (val+1))
FlameDataRecPtr MakeNewFlames (GrafPtr thePort, Rect *flameBounds,
short minFlameWidth, short maxFlameWidth,
double flameDensity, double fadeRate,
short maxFPS, CTabHandle itsCLUT)
/* Initialize a structure which contains all the data needed to */
/* run the flame routines */
{
CGrafPtr itsOldPort;
GDHandle itsOldDevice;
FlameDataRecPtr F = NULL;
double DTemp;
OSErr errCode;
RGBColor RBlack = {0,0,0};
unsigned int s;
// initialize the random number generator
s = (unsigned int) clock();
srand (s);
F = (FlameDataRecPtr)NewPtrClear (sizeof(FlameDataRec));
if (F)
{
F->flameTaskPtr = NULL;
F->flamePort = thePort;
F->density = flameDensity * 100;
F->fireCLUT = itsCLUT;
F->maxColor = (**itsCLUT).ctSize;
F->fadePerStep = fadeRate * F->maxColor;
/* Set the frame rate */
DTemp = (double)60 / (double)maxFPS;
if ((int)(DTemp + 0.5) > (int)DTemp)
F->timePerFrame = (int)DTemp+1;
else
F->timePerFrame = (int)DTemp;
F->timePerFrame = Max(1, F->timePerFrame);
// We will draw on the whole buffer, but not copy the bottom line
F->offRect = *flameBounds;
F->fireRect = *flameBounds;
OffsetRect (&F->offRect, -F->offRect.left, -F->offRect.top);
F->copyRect = F->offRect;
F->copyRect.bottom -= 1;
// Create the offscreen GWorld which the fire will be calculated on
errCode = NewGWorld(&F->DrawingArea,8,&F->offRect,F->fireCLUT,NULL, 0);
if (F->isValid = (errCode == noErr))
{
// lock the offscreen pixmap and get a pointer to its drawing area
F->offPixMap = GetGWorldPixMap(F->DrawingArea);
LockPixels (F->offPixMap);
// set the dimensions of the buffer
F->BUF_HEIGHT = flameBounds->bottom - flameBounds->top;
F->BUF_WIDTH = flameBounds->right - flameBounds->left;
F->maxFlameWidth = maxFlameWidth;
F->minFlameWidth = minFlameWidth;
// Get the address of our calculation buffer
F->basePixels = (unsigned char *)GetPixBaseAddr(F->offPixMap);
F->BitMapWidth = (**F->offPixMap).rowBytes & 0x7FFF;
// clear the offscreen buffer
GetGWorld(&itsOldPort,&itsOldDevice);
SetGWorld (F->DrawingArea, NULL);
RGBForeColor (&RBlack);
PaintRect (&F->offRect);
SetGWorld (itsOldPort, itsOldDevice);
}
}
return F;
}
void FreeFlames (FlameDataRecPtr *F)
{
if (*F)
{
if ((**F).flameTaskPtr)
{
DisposePtr((Ptr)(**F).flameTaskPtr);
(**F).flameTaskPtr = NULL;
}
if ((**F).isValid)
{
UnlockPixels ((**F).offPixMap);
DisposeGWorld((**F).DrawingArea);
}
DisposePtr((Ptr)*F);
*F = NULL;
}
}
void ChangeFlameDensity (FlameDataRecPtr F, double newDensity)
{
if (F)
F->density = newDensity * 100;
}
void ChangeFlameWidth (FlameDataRecPtr F, short newMinWidth, short newMaxWidth)
{
if (F)
{
F->maxFlameWidth = newMaxWidth;
F->minFlameWidth = newMinWidth;
}
}
void ChangeFlameFadeRate (FlameDataRecPtr F, double newFadeRate)
{
if (F)
F->fadePerStep = newFadeRate * F->maxColor;
}
void ChangeFlameFPS (FlameDataRecPtr F, short newFPS)
{
double DTemp;
if (F)
{
DTemp = (double)60 / (double)newFPS;
if ((int)(DTemp + 0.5) > (int)DTemp)
F->timePerFrame = (int)DTemp+1;
else
F->timePerFrame = (int)DTemp;
}
}
void StartFlames (FlameDataRecPtr F)
{
F->burning = TRUE;
}
void StopFlames (FlameDataRecPtr F)
{
F->burning = FALSE;
}
short StepFlames(FlameDataRecPtr register F)
/* Step the fire by one frame, and return the amount of time remaining */
/* before the next frame should be drawn (in ticks) */
{
register unsigned char *traverse;
register short x, y;
register short BUF_HEIGHT = F->BUF_HEIGHT,
BUF_WIDTH = F->BUF_WIDTH;
long StartTime, Duration;
short step, color;
unsigned char *limit;
unsigned char *limit2;
// if we have stopped burning, return 0; this will cause
// the VBL Task to terminate
if (!F->burning)
return 0;
StartTime = TickCount();
// Transform current buffer
traverse = F->basePixels + F->BitMapWidth + 1;
for(y=1;y<BUF_HEIGHT;y++)
{
for(x=1;x<BUF_WIDTH-1;x++)
{
*(traverse - F->BitMapWidth) = (*traverse + // x, y-1
*(traverse - 1) + // x, y
*(traverse + 1) + // x-1, y
*(traverse + F->BitMapWidth)) >> 2;// x+1, y
*traverse = Max (*traverse - F->fadePerStep, 0);
traverse++;
}
traverse += (2 + F->BitMapWidth - BUF_WIDTH);
}
// Set new bottom lines with random white or black
traverse = F->basePixels + (long)F->BitMapWidth * ((long)BUF_HEIGHT - 2);
limit = F->basePixels + (long)F->BitMapWidth * ((long)BUF_HEIGHT - 1);
while (traverse < limit)
{
step = random(F->maxFlameWidth - F->minFlameWidth)+F->minFlameWidth;
if (random(100) < F->density)
color = F->maxColor;
else
color = 0;
limit2 = traverse+step;
while ((traverse < limit2) && (traverse < limit))
{
*traverse = *(traverse + F->BitMapWidth) = color;
traverse++;
}
}
// static long count = 0;
// count++;
// if((count % 10) == 0){
CopyBits ((const BitMap *)*F->offPixMap, &F->flamePort->portBits,
&F->copyRect, &F->fireRect, srcCopy, NULL);
// }
Duration = TickCount() - StartTime;
return Max (1, F->timePerFrame - Duration);
}
static void LockHandle(Handle h)
{
if(h){
HLock(h);
}
}
static void UnlockHandle(Handle h)
{
if(h){
HUnlock(h);
}
}
static void UnlockPixMap(PixMapHandle p)
{
if(p){
UnlockHandle((Handle)p);
UnlockHandle((Handle)p[0]->pmTable);
}
}
static void LockPixMap(PixMapHandle p)
{
if(p){
LockHandle((Handle)p);
LockHandle((Handle)p[0]->pmTable);
}
}
static void LockPixPat(PixPatHandle p)
{
if(p){
LockHandle((Handle)p);
LockPixMap(p[0]->patMap);
LockHandle((Handle)p[0]->patData);
LockHandle((Handle)p[0]->patXData);
LockHandle((Handle)p[0]->patXMap);
}
}
void LockFlames(FlameDataRecPtr inFlames)
{
LockHandle((Handle)inFlames->DrawingArea->grafVars);
LockHandle((Handle)inFlames->DrawingArea->visRgn);
LockHandle((Handle)inFlames->DrawingArea->clipRgn);
LockPixPat(inFlames->DrawingArea->bkPixPat);
LockPixPat(inFlames->DrawingArea->pnPixPat);
LockPixPat(inFlames->DrawingArea->fillPixPat);
LockHandle((Handle)inFlames->fireCLUT);
LockPixMap(inFlames->offPixMap);
}